﻿using System;
using System.Windows.Forms;
using System.Drawing;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Configuration;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Dlg;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Meta;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Pdf;
using SdmxMl.Manager;

namespace Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook
{

    public partial class UcCodeBook : UserControl, PluginInterface.IPlugin
    {
        #region Internal Members

        private BookHierarchy BookPossibleContent;
        private string previousTempPdf;
        private string bookPath;
        private int splitterDistance;
        private string pluginDir;
        private MetaProviderFactory metaFactory;

        /// <summary>Currently edited book configuration options </summary>
        private BookConfiguration bookConfig;

        /// <summary>Pdf Book generator </summary>
        private BookGeneratorB bookGen;

        TreeNode BookRootNode;

        #endregion

        #region Constructor

        public UcCodeBook()
        {
            InitializeComponent();

            splitterDistance = 234; // splitContainer1.SplitterDistance;

            // Plug-in directory for ressources
            pluginDir = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)
            + System.IO.Path.DirectorySeparatorChar + SdmxMl.Manager.PluginManager.PLUG_IN_SUBDIR_NAME;
            
            // To hold signal of document fully loaded in web browser
            webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
            string welcomePath = pluginDir + System.IO.Path.DirectorySeparatorChar + "BookWelcome.mht";
            webBrowser.Navigate(welcomePath);

            // Add menu sub Items
            CreateAddModuleSubItems();
            
            // New book tree
            BookInitialize();
            //Default  Book config
            bookConfig = new BookConfiguration();
        }

        private void BookInitialize()
        {
            // New book tree
            BookPossibleContent = new BookHierarchy("New Book", true);
            BookRootNode = new TreeNode(BookPossibleContent.Book.Id);
            treeViewBook.Nodes.Clear();
            treeViewBook.Nodes.Add(BookRootNode);
        }

        private void CreateAddModuleSubItems()
        {
            // Add menu sub items
            int i = 0;
            foreach (TableOfContents toc in Enum.GetValues(typeof(TableOfContents)))
            {
                ToolStripMenuItem tsmi = new ToolStripMenuItem(toc.ToString(), imageListBook.Images[i]);
                tsmi.Click += new EventHandler(AddBookModule_Click);
                tsmi.Tag = i;
                toolStripMenuItemAdd.DropDownItems.Add(tsmi);

                // Add direct access via 1st item
                if (i == 0)
                    tsmi.ShortcutKeys = ((System.Windows.Forms.Keys)(System.Windows.Forms.Keys.Insert));
                ++i;
            }

        }

        #endregion

        #region PlugIn load event

        private void UcCodeBook_Load(object sender, EventArgs e)
        {
            splitContainer1.SplitterDistance = splitterDistance;

            metaFactory = new MetaProviderFactory();

            string fontDirectory = pluginDir + System.IO.Path.DirectorySeparatorChar;
            bookGen = new BookGeneratorB(fontDirectory, metaFactory);
        }
        #endregion

        #region IPlugin Members

        /// <summary>Event is part of interface but not used </summary>
        public event PluginInterface.PluginEvent PluginEventExposed
        {
            add { }
            remove { }
        }


        public void Init(System.Xml.XmlDocument xDoc, object obExtend)
        {
        }

        public UserControl VisualComponent()
        {
            return this;
        }

        public bool RequiresInit
        {
            get { return false; }
        }

        #endregion

        #region Module Adding

        private void AddBookModule_Click(object sender, EventArgs e)
        {
            try
            {
                // Event through menu enumeration or quick button ?
                ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
                TableOfContents moduleType = (tsmi == null) ? TableOfContents.Book : (TableOfContents)((int)tsmi.Tag);

                DlgModuleSelect aDlg = new DlgModuleSelect(moduleType, "CH1_SAKE", this.imageListBook);
                aDlg.ModuleSelected += new DlgModuleSelect.ModuleSelectedEvent(aDlg_ModuleSelected);
                aDlg.ShowDialog();
                aDlg.ModuleSelected -= new DlgModuleSelect.ModuleSelectedEvent(aDlg_ModuleSelected);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Plug-in Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void aDlg_ModuleSelected(object sender, ModuleBookEventArgs e)
        {
            try
            {
                // Full book, reset all
                if (e.ContentModuleType == TableOfContents.Book)
                {
                    // New book tree
                    BookInitialize();
                    AddBook(e.FullId);
                }
                else
                    AddModule(e.ContentModuleType, e.FullId);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Generator Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary> Construct tree according to specified book </summary>
        /// <param name="bookFullId">book identification</param>
        private void AddBook(string bookFullId)
        {
            IMetaProvider provider = metaFactory.GetMetaProvider(TableOfContents.Book, "en", bookFullId, this.bookConfig );
            // retrieve stored configuration
            BookProvider bp = provider as BookProvider;
            if (bp != null)
                bookConfig = bp.BookConfig;

            BookHierarchy bh = new BookHierarchy(provider.GetRootNode());
            ConstructTreeBook(bh);
        }
        /// <summary>Add a module content in tree</summary>
        /// <param name="moduleType">Type of module where to add identification</param>
        /// <param name="fullId">module item identification</param>
        private void AddModule(TableOfContents moduleType, string fullId)
        {
            BookHierarchy theBook = GetFullBookHierarchy();
            theBook.AddModule(moduleType, fullId);
            ConstructTreeBook(theBook);
        }

        public TreeNode GetModuleNode(TableOfContents moduleType)
        {
            foreach (TreeNode node in BookRootNode.Nodes)
                if ((int)node.Tag == (int)moduleType)
                    return node;
            return null;
        }

        private TreeNode CreateModuleNode(TableOfContents moduleType)
        {
            //locate position for creation in tree
            int indexNode = 0;
            foreach (TreeNode node in BookRootNode.Nodes)
            {
                int tocIndex = (int)node.Tag;
                if (tocIndex > (int)moduleType)
                    break;

                ++indexNode;
            }

            // Index 0 if for full book
            int moduleIndex = (int)moduleType - 1;
            TreeNode moduleNode = new TreeNode(BookPossibleContent.Nodes[moduleIndex].Id, (int)moduleType, (int)moduleType);
            moduleNode.Tag = (int)moduleType;
            BookRootNode.Nodes.Insert(indexNode, moduleNode);

            return moduleNode;
        }

        private void ConstructTreeBook(BookHierarchy bookHierarchy)
        {
            treeViewBook.BeginUpdate();
            treeViewBook.Nodes.Clear();
            BookRootNode = new TreeNode(bookHierarchy.BookFullId);
            treeViewBook.Nodes.Add(BookRootNode);
            foreach (HierarchyNode nodeModule in bookHierarchy.Nodes)
            {
                TreeNode tModule = new TreeNode(nodeModule.Id, (int)nodeModule.Tag, (int)nodeModule.Tag);
                tModule.Tag = nodeModule.Tag;
                BookRootNode.Nodes.Add(tModule);
                foreach (HierarchyNode node in nodeModule.Nodes)
                {
                    TreeNode tn = new TreeNode(node.Id, imageListBook.Images.Count - 1, imageListBook.Images.Count - 1);
                    tModule.Nodes.Add(tn);
                }
            }
            treeViewBook.ExpandAll();


            treeViewBook.EndUpdate();
        }

        #endregion

        #region Pdf Generation

        private void GeneratePdf(BookHierarchy book)
        {
            //splitterDistance = splitContainer1.SplitterDistance;

            if (bookConfig.ExternalPdfViewer == false)
            {
                splitContainer1.SplitterDistance = splitContainer1.Panel1MinSize;
                webBrowser.Stop();
                webBrowser.Navigate("about:blank");
            }

            bookPath = System.IO.Path.GetTempFileName().Replace(".tmp", ".pdf");
            string renumPath = System.IO.Path.GetTempFileName().Replace(".tmp", ".pdf");

            using (new SdmxMl.Helper.CWaitCursor())
            {
                Image logo = global::Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Properties.Resources.logo;
                    
                bookGen.Generate(bookPath, book, SdmxMl.Common.LangSupport.CurLang, bookConfig, logo);
                //PdfRenumbering renum = new PdfRenumbering("SMS Codebook generator - © BFS/OFS 2013", bookGen.Fonts, bookConfig);
                //renum.AddPageNumbers(bookPath, renumPath);
                renumPath = bookPath;
            }
            if (bookConfig.ExternalPdfViewer)
                System.Diagnostics.Process.Start(renumPath);
            else
                webBrowser.Navigate(renumPath);
            
        }

        void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            try
            {
                if (previousTempPdf != null)
                    System.IO.File.Delete(previousTempPdf);
                previousTempPdf = bookPath;
            }
            catch { }
        }

        /// <summary>
        /// Full book or Current module or module element generation
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void PdfGenerationMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                // Only selected content or whole book
                if (sender == selectedContentToolStripMenuItem && treeViewBook.SelectedNode != BookRootNode)
                    GeneratePdf(GetSelectedModuleHierarchy());
                else
                    GeneratePdf(GetFullBookHierarchy());
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Delete module

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (treeViewBook.SelectedNode != null)
            {
                if (MessageBox.Show("Delete selected content and children?", "Check",
                  MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    if (treeViewBook.SelectedNode == BookRootNode)
                    {
                        BookInitialize();
                    }
                    else
                    {
                        treeViewBook.SelectedNode.Parent.Nodes.Remove(treeViewBook.SelectedNode);
                    }
                }
          }
        }
        #endregion

        #region vertical slider


        private void buttonShowTree_Click(object sender, EventArgs e)
        {
            if (splitContainer1.SplitterDistance >= splitterDistance)
                splitContainer1.SplitterDistance = splitContainer1.Panel1MinSize;
            else
                splitContainer1.SplitterDistance = splitterDistance;
        }

        #endregion

        #region Book Hierarchy

        /// <summary>Generate book content only for selected module or module child</summary>
        /// <returns>requested book content</returns>
        private BookHierarchy GetSelectedModuleHierarchy()
        {
            TreeNode selectedNode = treeViewBook.SelectedNode;
            BookHierarchy currentBookContent = new BookHierarchy(BookRootNode.Text, false);
            if (selectedNode != null)
            {
                TreeNode nodeModuleType = selectedNode.Parent == BookRootNode ? selectedNode : selectedNode.Parent;

                // If module selected and children exist, generate all childs
                if (selectedNode.Parent == BookRootNode)
                {
                    foreach (TreeNode nodeModule in nodeModuleType.Nodes)
                        currentBookContent.AddModule(((TableOfContents)((int)nodeModuleType.Tag)), nodeModule.Text);
                }
                else
                {
                    // if child selected gernerate it only
                    currentBookContent.AddModule(((TableOfContents)((int)nodeModuleType.Tag)), selectedNode.Text);
                }
            }
            return currentBookContent;
        }

        /// <summary>Generates whole book content according to tree</summary>
        /// <returns>requested book content</returns>
        private BookHierarchy GetFullBookHierarchy()
        {
            BookHierarchy currentBookContent = new BookHierarchy(BookRootNode.Text, false);
            foreach (TreeNode nodeModuleType in BookRootNode.Nodes)
            {
                foreach (TreeNode nodeModule in nodeModuleType.Nodes)
                    currentBookContent.AddModule(((TableOfContents)((int)nodeModuleType.Tag)), nodeModule.Text);
            }

            return currentBookContent;
        }
        #endregion

        #region Configuration Dialog

        private void configureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                DlgBookConfig aDlg = new DlgBookConfig(bookConfig);
                aDlg.ShowDialog();


            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        #region Import from main tree

        private void buttonImportFromMainTree_Click(object sender, EventArgs e)
        {
            if (ReferenceManager.TreeSdmx != null && ReferenceManager.TreeSdmx.SelectedNode != null)
            {
                SdmxMl.Common.Artefact a = GetSelectedArtefact(ReferenceManager.TreeSdmx.SelectedNode);
                if (a != null)
                {
                    // Codelist 
                    if (a.ArType == SdmxArtefactType.CodeLists)
                        AddModule(TableOfContents.Codelists, a.FullIdent);
                    // Concept
                    else if (a.ArType == SdmxArtefactType.Concepts)
                        AddModule(TableOfContents.Catalog, a.FullIdent);
                    // hierarchicalCodelist
                    else if (a.ArType == SdmxArtefactType.HierarchicalCodelists)
                        AddModule(TableOfContents.Hierarchies, a.FullIdent);
                }
            }
        }
        private SdmxMl.Common.Artefact GetSelectedArtefact(TreeNode node)
        {
            SdmxMl.Common.Artefact a = null;

            while (node != null && node.Tag != null)
            {
                if (node.Tag is SdmxMl.Common.Artefact)
                {
                    a = node.Tag as SdmxMl.Common.Artefact;
                    break;
                }
                node = node.Parent;
            }

            return a;
        }
        #endregion

        private void toolStripButtonSaveBook_Click(object sender, EventArgs e)
        {
            try
            {
                BookSaver saver = new BookSaver();
                DlgSaveBook aDlg = new DlgSaveBook(saver.GetActivityList(SdmxMl.Common.LangSupport.CurLang), BookRootNode.Text.Replace("Book ", ""));
                if (aDlg.ShowDialog() == DialogResult.OK)
                {
                    saver.SaveBook(GetFullBookHierarchy(), bookConfig, aDlg.Activity, aDlg.FullId);
                    BookRootNode.Text = aDlg.FullId;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void resetMetaCacheToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        /// <summary> Clear metadata cache Event </summary>
        /// <param name="sender"></param><param name="e"></param>
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            metaFactory.ClearMetaCache();
            //Default  Book config
            bookConfig = new BookConfiguration();
        }
    }
}
